﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Speech.Recognition;
using System.Threading;
using System.Runtime.InteropServices;
using SpeechLib;

namespace VoiceCalc
{
    public partial class Form1 : Form
    {
        Thread recognizeThread = null; // 認識用スレッド

        private bool Recognizing;  // 認識中かどうか
        String recognizedMessage;  // 認識結果確認用
        static SpeechRecognitionEngine engine;

        SpVoice tts;      // 音声合成のオブジェクト
        ISpeechObjectTokens voiceInfo;    // 音声の情報

        delegate void PrintMessage();
        private int VoiceActiveIndex = 0;
        //--------------------------------------------------------------------------
        //コンストラクタ
        //--------------------------------------------------------------------------
        public Form1()
        {
            InitializeComponent();
        }
        //--------------------------------------------------------------------------
        //開始時
        //--------------------------------------------------------------------------
        private void Form1_Load(object sender, EventArgs e)
        {
#if DEBUG
            textBox1.Enabled = true;
#else
            textBox1.Enabled = false;
#endif
            try
            {
                tts = new SpVoice();      // 音声合成のオブジェクト
                voiceInfo = tts.GetVoices("", "");
                textBox1.Text += voiceInfo.Item(1).GetAttribute("Name");
            }
            catch
            {
                MessageBox.Show("Microdoft Speech Platform 初期化中にエラーが発生しました。");
                //Application.Exit();
            }


            
            try
            {
                engine = new SpeechRecognitionEngine();
                engine.SpeechRecognized += DisplayRecognized;
                engine.LoadGrammar(new DictationGrammar());
                engine.SetInputToDefaultAudioDevice();
                Recognizing = false;  // 認識中じゃない状態として初期化
            }
            catch (Exception)
            {
            }
            this.ActiveControl = NameTextBox;
        }
        private void button2_Click(object sender, EventArgs e)
        {
            tts.Voice = voiceInfo.Item(1);    // 音声の設定
            tts.Volume = 100;                // 音量の設定
            tts.Rate = 0;                    // 速度の設定
            SpeechVoiceSpeakFlags flg = SpeechVoiceSpeakFlags.SVSFIsXML | SpeechVoiceSpeakFlags.SVSFlagsAsync | SpeechVoiceSpeakFlags.SVSFPurgeBeforeSpeak;
            tts.Speak(AllSumTextBox.Text, flg);          // 読み上げ
        }
        //--------------------------------------------------------------------------
        //音声認識時
        //--------------------------------------------------------------------------
        void DisplayRecognized(object sender, RecognitionEventArgs e)
        {
            recognizedMessage = e.Result.Text;
            Invoke(new PrintMessage(PrintRecognized));
        }
        //--------------------------------------------------------------------------
        //音声認識開始
        //--------------------------------------------------------------------------
        void RecognizeProcess()
        {
            while (Recognizing)
            {
                engine.Recognize();
            }
        }
        //--------------------------------------------------------------------------
        //テキスト書きこみ
        //--------------------------------------------------------------------------
        void PrintRecognized()
        {
            //名前
            if (VoiceActiveIndex == 0 || recognizedMessage == "名前")
            {
                AddText(0, recognizedMessage + "\n");
            }
            //値段
            else if (VoiceActiveIndex == 1 || recognizedMessage == "値段")
            {
                AddText(1, recognizedMessage + "\n");
            }
            //個数
            else if (VoiceActiveIndex == 2 || recognizedMessage == "個数")
            {
                AddText(2, recognizedMessage + "\n");
            }
            //割引
            else if (VoiceActiveIndex == 3 || recognizedMessage == "割引")
            {
                AddText(3, recognizedMessage + "\n");
            }
            textBox1.Text = recognizedMessage;
        }
        //--------------------------------------------------------------------------
        //音声認識開始ボタン
        //--------------------------------------------------------------------------
        private void button1_Click(object sender, EventArgs e)
        {
            if (button1.Text == "音声認識開始")
            {
                recognizeThread = new Thread(new ThreadStart(RecognizeProcess));
                recognizeThread.Start();

                button1.Text = "音声認識停止";
                Recognizing = true;
            }
            else
            {
                button1.Text = "音声認識開始";
                Recognizing = false;
            }
            NameTextBox.Focus();
            VoiceActiveIndex = 0;
        }
        //--------------------------------------------------------------------------
        //テキストが四則演算かどうか？
        //--------------------------------------------------------------------------
        bool IsCalc(char calc)
        {
            if (calc == '+' || calc == '-' || calc == '*' || calc == '/')
            {
                return true;
            }
            return false;
        }
        //--------------------------------------------------------------------------
        //文字列から数字だけ取得
        //--------------------------------------------------------------------------
        string GetNumberFromString(string strText)
        {
            string strNumber = "";
            for (int i = 0; i < strText.Length; i++)
            {
                if (char.IsNumber(strText, i))
                {
                    strNumber += strText[i];
                }
            }
            return strNumber;
        }
        //--------------------------------------------------------------------------
        //テキストボックスの文字列を数字に変換
        // true:有効な文字列 false:無効な文字列
        //--------------------------------------------------------------------------
        bool ChangeNumberFromTextbox(String text, TextBox tb)
        {
            //'×'や"かける"は*に置換してしまう
            text = text.Replace('×', '*');
            text = text.Replace("かける", "*");
            text = text.Replace('÷', '/');
            text = text.Replace("わる", "/");
            //文字列から数字と記号以外を省く
            string strClac = "";
            for (int i = 0; i < text.Length; i++)
            {
                if (char.IsNumber(text, i) == true || IsCalc(text[i]) == true)
                {
                    strClac += text[i];
                }
            }
            //空っぽなら無効
            if (strClac == "")
            {
                tb.Text = strClac;
                return false;
            }
            //最後が記号の場合は処理中断で光らせる(例:1+2+
            if (IsCalc(strClac[strClac.Length - 1]) == true)
            {
                tb.Text = strClac;
                tb.Select(strClac.Length - 1, 1);
                return false;
            }
            //記号が連続の場合は処理中断で光らせる(例:1+-2
            bool bDoubleCalc = true;
            for (int i = 0; i < strClac.Length; i++)
            {
                if (char.IsNumber(strClac, i) == true)
                {
                    bDoubleCalc = false;
                }
                else if (IsCalc(strClac[i]) == true)
                {
                    //文字が続けばエラー
                    if (bDoubleCalc == true)
                    {
                        tb.Text = strClac;
                        tb.Select(i - 1, 2);
                        return false;
                    }
                    bDoubleCalc = true;
                }
            }
            //Eval関数で文字列を計算
#if zero
            MSScriptControl.ScriptControl sc = new MSScriptControl.ScriptControl();
            sc.Language = "vbscript";
            string strText = sc.Eval(strClac);
#else
            Microsoft.JScript.Vsa.VsaEngine ve = Microsoft.JScript.Vsa.VsaEngine.CreateEngine();
            string strText = Microsoft.JScript.Eval.JScriptEvaluate(strClac, ve).ToString();
#endif
            //マイナスはプラスに
            float fPlus = System.Math.Abs(float.Parse(strText));
            //少数は四捨五入
            tb.Text = ((int)(fPlus + 0.5f)).ToString();
            //計算式がある
            return (tb.Text != "");
        }
        //--------------------------------------------------------------------------
        //全合計セット
        //--------------------------------------------------------------------------
        void SetTopSum()
        {
            int iAllSum = 0;
            foreach (ListViewItem li in SumListView.Items)
            {
                string strYen = GetNumberFromString(li.SubItems[1].Text);
                if (strYen != "")
                {
                    iAllSum += int.Parse(strYen);
                }
            }
            AllSumTextBox.Text = iAllSum.ToString() + "円";
        }
        //--------------------------------------------------------------------------
        //追加チェック
        //--------------------------------------------------------------------------
        int iAddNewName = 1;
        bool bAddCheck = true;
        ListViewItem g_lvi = null;
        void CheckListViewAdd()
        {
            //×２にした時に個数に自動反映
            //ListViewの結果を合計と内容に分けて表示する
            string strName = (NameTextBox.Text != "") ? NameTextBox.Text : "品物" + iAddNewName;
            string strValue = (ValueTextBox.Text != "") ? ValueTextBox.Text : "-";
            string strNumber = (NumberTextBox.Text != "") ? NumberTextBox.Text : "-";
            string strItem =  strName + ":" + strValue + "円:×" + strNumber;
            //選択時
            if (SumListView.SelectedItems.Count != 0)
            {
                g_lvi = SumListView.SelectedItems[0];
                g_lvi.Checked = NameCheckBox.Checked;
            }
            //追加時
            else if (bAddCheck)
            {
                if (CutTextBox.Text != "0")
                {
                    g_lvi = SumListView.Items.Insert(0, strItem + ":-" + CutTextBox.Text + "%");
                    g_lvi.SubItems.Add("-円");
                }
                else
                {
                    g_lvi = SumListView.Items.Insert(0,strItem);
                    g_lvi.SubItems.Add("-円");
                }
                iAddNewName++;
                g_lvi.ImageIndex = 0;
                g_lvi.Checked = NameCheckBox.Checked;
                bAddCheck = false;
            }
            //フォーカスの位置
            ValueTextBox.Focus();
            VoiceActiveIndex = 1;
            //アイテム追加時
            if (
                (NumberTextBox.Text != "" && ValueTextBox.Text != "" && CutTextBox.Text != "") ||
                (NameCheckBox.Checked == false && NumberTextBox.Text != "")
                )
            {
                //合計挿入
                if (CutTextBox.Text != "0")
                {
                    int sum = (int)(int.Parse(strNumber) * int.Parse(strValue) * (1.0f - float.Parse(CutTextBox.Text) / 100.0f));
                    g_lvi.Text = strItem + ":" + CutTextBox.Text + "%off";
                    g_lvi.SubItems[1].Text = sum + "円";
                }
                else if (strValue == "-")
                {
                    g_lvi.Text = strItem;
                    g_lvi.SubItems[1].Text = "-円";
                }
                else
                {
                    int sum = int.Parse(strNumber) * int.Parse(strValue);
                    g_lvi.Text = strItem;
                    g_lvi.SubItems[1].Text = sum + "円";
                }
                //全合計
                SetTopSum();
                //クリア
                if (NameTextBox.Text != "")
                {
                    NameTextBox.Focus();
                    VoiceActiveIndex = 0;
                }
                NameTextBox.Text = "";
                ValueTextBox.Text = "";
                NumberTextBox.Text = "1";
                CutTextBox.Text = "0";
                //選択解除
                foreach (ListViewItem li in SumListView.SelectedItems)
                {
                    li.Selected = false;
                }
                bAddCheck = true;
            }
            else
            {
                g_lvi.Text = strItem;
                g_lvi.SubItems[1].Text = "-円";
            }
            //SumListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
        }
        //--------------------------------------------------------------------------
        //テキストボックスに値を入れて新しいテキストを取得
        //--------------------------------------------------------------------------
        string GetTextSetTextbox(string strText, TextBox tb)
        {
            string strSetText = "";
            for (int i = strText.Length - 2; i >= 0; i--)
            {
                if (char.IsNumber(strText, i))
                {
                    strSetText = strText[i] + strSetText;
                }
                else
                {
                    break;
                }
            }
            if (strSetText != "")
            {
                tb.Text = strSetText;
                strText = strText.Substring(0, strText.Length - strSetText.Length - 1);
            }
            return strText;
        }
        //--------------------------------------------------------------------------
        //まとめ言いチェック
        //--------------------------------------------------------------------------
        bool GetWhole(string strText)
        {
            if (strText.EndsWith("%") || strText.EndsWith("o"))
            {
                strText = GetTextSetTextbox(strText, CutTextBox);
            }
            if (strText.EndsWith("個") || strText.EndsWith("n"))
            {
                strText = GetTextSetTextbox(strText, NumberTextBox);
            }
            if (strText.EndsWith("円") || strText.EndsWith("y"))
            {
                strText = GetTextSetTextbox(strText, ValueTextBox);
            }
            if (strText.IndexOf("\\") != -1)
            {
                string strSetText = "";
                for (int i = strText.IndexOf("\\") + 1; i < strText.Length; i++)
                {
                    if (char.IsNumber(strText, i))
                    {
                        strSetText += strText[i];
                    }
                    else
                    {
                        break;
                    }
                }
                if (strSetText != "")
                {
                    ValueTextBox.Text = strSetText;
                    strText = strText.Substring(0, strText.IndexOf("\\"));
                }
                strText = GetTextSetTextbox(strText, ValueTextBox);
            }
            NameTextBox.Text = strText;
            return (strText != "");
        }
        //--------------------------------------------------------------------------
        //テキスト書きこみ
        //--------------------------------------------------------------------------
        void AddText(int type, string text)
        {
            if (type == 0)
            {
                GetWhole(text);
                CheckListViewAdd();
            }
            else if (type == 1)
            {
                if (ChangeNumberFromTextbox(text, ValueTextBox))
                {
                    CheckListViewAdd();
                }
            }
            else if (type == 2)
            {
                if (ChangeNumberFromTextbox(text, NumberTextBox))
                {
                    CheckListViewAdd();
                }
            }
            else if (type == 3)
            {
                if (ChangeNumberFromTextbox(text, CutTextBox))
                {
                    CheckListViewAdd();
                }
            }

        }
        //--------------------------------------------------------------------------
        //プラスボタン
        //--------------------------------------------------------------------------
        private void PlusButton_Click(object sender, EventArgs e)
        {
            //表示がなければそこにフォーカスを
            if (NameTextBox.Text == "")
            {
                NameTextBox.Focus();
            }
            else if (ValueTextBox.Text == "")
            {
                ValueTextBox.Focus();
            }
            //あれば値段を入れたことにして合計計算
            else
            {
                AddText(1, ValueTextBox.Text);
            }
        }
        //--------------------------------------------------------------------------
        //アイテムテキスト書きこみ
        //--------------------------------------------------------------------------
        private void OneItemTextBox_KeyDown(object sender, KeyEventArgs e)
        {
            TextBox tb = sender as TextBox;
            if (tb.Text != "" && (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Tab))
            {
                AddText(int.Parse(tb.Tag.ToString()), tb.Text);
                e.SuppressKeyPress = true;
            }
        }
        //--------------------------------------------------------------------------
        //選択変更
        //--------------------------------------------------------------------------
        private void SumListView_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (SumListView.SelectedItems.Count != 0)
            {
                string strItem = SumListView.SelectedItems[0].Text.Substring(SumListView.SelectedItems[0].Text.IndexOf('(') + 1);
                string[] strItems = strItem.Split(':');

                NameTextBox.Text = strItems[0];
                ValueTextBox.Text = GetNumberFromString(strItems[1]);
                NumberTextBox.Text = GetNumberFromString(strItems[2]);
                CutTextBox.Text = (strItems.Length == 4) ? GetNumberFromString(strItems[3]) : "0";
            }
        }
        //--------------------------------------------------------------------------
        //選択変更
        //--------------------------------------------------------------------------
        private void SumListView_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            //タイマー開始
            selectTimer.Enabled = !e.IsSelected;
        }
        //--------------------------------------------------------------------------
        //0.1秒後
        //--------------------------------------------------------------------------
        private void selectTimer_Tick(object sender, EventArgs e)
        {
            NameTextBox.Focus();
            VoiceActiveIndex = 0;
            NameTextBox.Text = "";
            ValueTextBox.Text = "";
            NumberTextBox.Text = "1";
            CutTextBox.Text = "0";
            selectTimer.Enabled = false;
        }
        //--------------------------------------------------------------------------
        //リストビューキーダウン
        //--------------------------------------------------------------------------
        private void SumListView_KeyDown(object sender, KeyEventArgs e)
        {
            if (SumListView.SelectedItems.Count == 0) return;
            if (e.KeyData == Keys.Delete)
            {
                SumListView.SelectedItems[0].Remove();
                SetTopSum();
                NameTextBox.Text = "";
                ValueTextBox.Text = "";
                NumberTextBox.Text = "1";
                CutTextBox.Text = "0";
                NameTextBox.Focus();
                VoiceActiveIndex = 0;
            }
        }
        //--------------------------------------------------------------------------
        //名前テキストボックス文字位置
        //--------------------------------------------------------------------------
        private void VoiceTextBox_Enter(object sender, EventArgs e)
        {
            TextBox tb = sender as TextBox;
            VoiceActiveIndex = int.Parse(tb.Tag.ToString());
            if (tb == NameTextBox)
            {
                NameTextBox.TextAlign = HorizontalAlignment.Left;
                NameTextBox.Focus();
            }
        }
        private void NameTextBox_Leave(object sender, EventArgs e)
        {
            if (SumListView.SelectedItems.Count == 1) return;

            if (NameTextBox.Text != "")
            {
                NameTextBox.TextAlign = HorizontalAlignment.Right;
                ValueTextBox.Focus();
            }
        }









    }
}